/**
 * Firedrop_overlay.js
 * Main javascript file
 */


var firedrop = {
	
	prefs: null,
	
	startup: function() {
    // initialization code
    this.initialized = true;
    this.strings = document.getElementById("firedrop-strings");

	// initialize component
	this.myComponent = Components.classes['@foobar/mycomponent;1'].getService().wrappedJSObject;
	  
	// starts the managers to listen for redirect to the authentication
	// callback page
	messageManager.addMessageListener("firedrop:Code", dropbox.fireAlert);
	messageManager.loadFrameScript("chrome://firedrop/content/content_script.js", true);
	
  },

	// Menu item function - lots of work to do here
	onMenuItemCommand: function(e) {
    	// var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
        //                          .getService(Components.interfaces.nsIPromptService);

        // Get folder contents from user's Dropbox Apps folder
        dropbox.getFolderContents();
  },

 	// Toolbar button - same thing, lots o work
	onToolbarButtonCommand: function(e) {
    	// just reuse the function above.  you can change this, obviously!
    	firedrop.onMenuItemCommand(e);
 	},
	
	// Context-Menu button
	onContextMenuCommand: function () {
		//alert("Uploading File: "+gContextMenu.linkURL);
		dump("Uploading File: "+ gContextMenu.linkURL +"\n");
		
		//Request data from url and specify that we are expecting to receive the data as an array buffer
		var xhr = new XMLHttpRequest();  
		xhr.open("GET", gContextMenu.linkURL, true);  
		xhr.responseType = "arraybuffer";  
		
		var linkURL = gContextMenu.linkURL;
		xhr.onload = function(e) {
			if (xhr.status == 200) {  
				var arrayBuffer = xhr.response; // Note: not xhr.responseText  
				if (arrayBuffer) {  
					var byteArray = new Uint8Array(arrayBuffer);
					//alert(byteArray);
					var callback = function(data){
						alert(data);							
					};
					
					dropbox.uploadFile(byteArray, unescape(linkURL.substring(linkURL.lastIndexOf(escape("/"))+1)), callback);
				}  
			} else {
				dump("Failed to get data from the url");
			}
		};  
		  
		xhr.send(null); 
		
	},

	// Opens the Dropbox authentication page in a new tab
	dropboxAuth: function(url) {
		getBrowser().selectedTab = getBrowser().addTab(url);
	},
	
	// Function to save the Dropbox preferences, possibly can be
	// refactored to the dropbox class, should probably have a getter as well
	setDropboxAccount: function(accessToken, accessSecret) {
		
		try {
			this.myComponent.setPrefForKey("accessecret", accessSecret);
			this.myComponent.setPrefForKey("accesstoken",accessToken);
			alert("You have successfully logged in. You may close this tab.");
		}
		
		catch(error) {
			alert("Sorry, there was an error. Eventually, we'll have something informative here." + error);
		}
		
		
		
		dump(this.myComponent.getPrefForKey("accessecret"));
	}
};

firedrop.onFirefoxLoad = function(event) {
  document.getElementById("contentAreaContextMenu")
          .addEventListener("popupshowing", function (e) {
    firedrop.showFirefoxContextMenu(e);
  }, false);
};

firedrop.showFirefoxContextMenu = function(event) {
	// show or hide the menuitem based on what the context menu is on
	// this is where we can target files themselves
  document.getElementById("context-firedrop").hidden = gContextMenu.onImage;
};


/*
 *  Dropbox 'class' that handles the authentication and 
 *	oauth stuff to Dropbox.
 */

var dropbox = {};

// url that is redirected to during authentication
// configured as a listener in content_script.js
var CALLBACK_URL = encodeURIComponent("http://cobweb.seas.gwu.edu/~cma27");

// Dropbox base url, using the dropbox v1 scheme
var BASE_URL = "https://api.dropbox.com/1/";

// Enable Dropbox file metadata caching for reporting folder contents
dropbox.cache = true;

// Set to "dropbox" when application has been given full Dropbox folder access
dropbox.accessType = "sandbox";

// Max number of files to list from a directory
dropbox.fileLimit = 10000;

// Dropbox provided application key and secret
//Doug's Keys
//var APP_KEY = "wxm2csmj1lz1ons";
//var APP_SECRET = "nkurx0qrex0gzjf";

// //Pedro's Keys
// var APP_KEY = "ydfgaqxhb0daqux";
// var APP_SECRET = "8n6eyf3808eaqmw";

//Chris' Keys
var APP_KEY = "o5rozdjosfd57of";
var APP_SECRET = "2tm5wwhmvszp1it";

// configures either dropbox for full access or sandbox to restrict to one folder
//var accessType=  "dropbox";

// Initizalizes variables to be used in the authentication process
var tokenKey= '';
var tokenSecret= '';
var accessToken = '';
var accessTokenSecret = '';

// Generates the proper authentication URL for user login, probably can
// be combined with buildAuthorizeUrl
dropbox.getAuthUrl = function() {
		this.obtainRequestToken();
		return this.buildAuthorizeUrl();
	};

// Gets the account info of the Dropbox user
dropbox.getAccountInfo = function() {
        var self = this;
		// dump(this.generateOauthData().toSource());
        $.ajax({
			url: BASE_URL + 'account/info',
            type: 'GET',
			dataType: 'json',	
            data: this.generateClientOauthData(),
            success: function(resp) {
				// dump("success " + resp.toSource() + "\n");
				return resp.toSource();
            },
			error: function(resp, error) {
				dump(resp.responseText + "\n");
				dump(resp.status + "\n");
				dump(resp.statusText + "\n");

			}
        });
    };
	
//Function to send oauth requests
dropbox.uploadFileOauthReqeust = function(param1,param2,callback) {
	//If the token wasn't defined in the function call, then use the access token
	if (!param1.token) {
		//alert(dropbox.accessToken);
		param1.token = firedrop.myComponent.getPrefForKey("accesstoken");
	}
	if (!param1.tokenSecret) {
		param1.tokenSecret = firedrop.myComponent.getPrefForKey("accessecret");
	}
	
	//If type isn't defined, it's JSON
	if (!param1.type) {
		param1.type = "json";
	}
	
	//If method isn't defined, assume it's GET
	if (!param1.method) {
		param1.method = "POST";
	}
	
	//Define the accessor
	accessor = {
		consumerSecret: APP_SECRET,
	};
	
	//Outline the message
	message = {
		action: param1.url,
	    method: param1.method,
		overwrite:false,
	    parameters: [
	      	["oauth_consumer_key", APP_KEY],
	      	["oauth_signature_method","HMAC-SHA1"]
	  	]
	};
	
	//Only add tokens to the request if they're wanted (vars not passed as true)
	if (param1.token != true) {
		message.parameters.push(["oauth_token",param1.token]);
	}
	if (param1.tokenSecret != true) {
		accessor.tokenSecret = param1.tokenSecret;
	}
	
	
	//Timestamp and sign the OAuth request
	OAuth.setTimestampAndNonce(message);
	OAuth.SignatureMethod.sign(message, accessor);
	
	dump("before ajax call in oauthrequest");
	
	var api_url = message.action;//+"?file=" + param2[1];

	//Create multipart/form-data request
	var boundary = '----12345568790';
	var header =  "--" + boundary + "\r\n";
	header += "Content-Disposition: multipart/form-data; name=\"file\";";
	header += "filename=\"" + param2[1] + "\"\r\n";
	header += "Content-Type: application/octet-stream\r\n\r\n";
	var foot = "\r\n--" + boundary + "--";
	
	var dataToSend = '';
	for (i = 0; i < param2[0].length; i += 1) {
        dataToSend += String.fromCharCode(param2[0][i] & 0xff);
    }
	var fullContent = header + dataToSend + foot;

	dump('MESSAGE');
	dump(fullContent);
	
	//Post message
	var xhr = new XMLHttpRequest();
	xhr.onload = function(e) {   
		if (xhr.status == 200) {  
		  dump("File has been uploaded!!");  
		  callback("File has been uploaded!!");
		} else {
		  dump("\n\n Basestring: "+OAuth.SignatureMethod.getBaseString(message)+"\n\n");
		  dump("Error " + xhr.status + " occurred uploading your file."); 
		  dump(xhr.responseText + "\n");
		  dump(xhr.status + "\n");
		  dump(xhr.statusText + "\n");
		}  
	  };
	xhr.open('POST', api_url);
	xhr.setRequestHeader('Authorization', OAuth.getAuthorizationHeader("Secure Area", message.parameters));
	xhr.setRequestHeader("Content-type", "multipart/form-data; boundary=\"" + boundary + "\"");
	xhr.setRequestHeader("Connection", "close");
	xhr.sendAsBinary(fullContent);
	
}

//Function to upload a file
dropbox.uploadFile = function(file, filename, callback) {
	//dump(file);
	//alert(file);
	dropbox.uploadFileOauthReqeust({
		url: "https://api-content.dropbox.com/1/files/sandbox?file="+filename,
		type: "text",
		method: "POST"
	}, [file,filename], function(data) {
		callback(data);
	});
}

// Gets the folder contents -- should modify to check for cache
dropbox.getFolderContents = function() {
        var self = this;
        $.ajax({
			url: BASE_URL + "/metadata/" + dropbox.accessType + "/",
            type: "GET",
			dataType: "json",	
            data: this.generateClientOauthData(),
            success: function(resp) {

                // Parse out path/filename, size, and date into array
                
                // (1) Strip-out everything except contents list
                var contents = JSON.stringify( resp );
                var start = contents.search( /{"revision":/i );
                var end = contents.search( /],"icon":"folder"}/i );
                contents = "[" + contents.slice( start, end ) + "]";
                
                // (2) Split the string into an array of objects
                var resp = JSON.parse( contents );
                dump("SUCCESS - PARSED CONTENTS: " + resp.toSource() + "\n");
                         
                // Add tab, then make active
                // getBrowser().selectedTab = getBrowser().addTab(decodeURIComponent(CALLBACK_URL));
                window.openDialog("chrome://firedrop/content/firedrop_report.xul", "", "chrome", resp);
            },
			error: function(resp, error) {
                alert("FIREDROP ERROR: " + resp.responseText + "\n");
				alert("FIREDROP ERROR: " + resp.status + "\n");
				alert("FIREDROP ERROR: " + resp.statusText + "\n");
				dump("FIREDROP ERROR: " + resp.responseText + "\n");
				dump("FIREDROP ERROR: " + resp.status + "\n");
				dump("FIREDROP ERROR: " + resp.statusText + "\n");
				// alert(firedrop.prefs.getCharPref("accessecret"));
			}
        });
};

// TODO combine into one function
// Generates Oauth data for signing requests after authentication
// fetches the dropbox token from preferences
dropbox.generateClientOauthData = function() {
		return {
			oauth_consumer_key: APP_KEY,
			oauth_token: firedrop.myComponent.getPrefForKey("accesstoken"),
			oauth_signature_method: 'PLAINTEXT',
			oauth_signature: APP_SECRET + '&' + firedrop.myComponent.getPrefForKey("accessecret"),
		};
	};

// Oauth data for initial authentication
dropbox.generateOauthData = function() {
		return {
			oauth_consumer_key: APP_KEY,
			oauth_token: tokenKey,
			oauth_signature_method: 'PLAINTEXT',
			oauth_signature: APP_SECRET + '&' + tokenSecret,
		};
	};

// Step 1 in authentication - fetches the request token
// and request secret token and stores them on success, dumps
// error on failure
dropbox.obtainRequestToken = function() {
        var self = this;

		// fires the ajax callback
        $.ajax({
			url: BASE_URL + 'oauth/request_token?',
            type: 'POST',
			async: false,
            data: this.generateOauthData(),
            success: function(request) {
				var parts = request.split('&');
                tokenSecret = parts[0].split('=')[1];
                tokenKey = parts[1].split('=')[1];
            },
			error: function(request, error) {
				dump(request.responseText);
			}
        });
    };

// Builds the authorization URL and returns that URL
dropbox.buildAuthorizeUrl = function() {
        var newURL = "https://www.dropbox.com/1/oauth/authorize?oauth_token=" + tokenKey + "&oauth_callback=" + CALLBACK_URL;
		return newURL;
    };

// Function to intercept the message sent when the app redirects
// to the callback page
dropbox.fireAlert = function() {
	dropbox.obtainAccessToken();
};

// Step 3 in authentication - after the callback page is loaded, signifying
// we've gotten our request tokens, obtain the actual access token from Dropbox. 
// Function stores the access token and access secret in preferences
dropbox.obtainAccessToken = function() {
        var self = this;
        $.ajax({
            url: BASE_URL + 'oauth/access_token?',
            type: 'POST',
            data: this.generateOauthData(),
            async: false,
            success: function(request) {
				var parts = request.split('&');
				self.accessTokenSecret = parts[0].split('=')[1];
				self.accessToken = parts[1].split('=')[1];
				self.uid = parts[2].split('=')[1];
				firedrop.setDropboxAccount(self.accessToken, self.accessTokenSecret);
            },
			error: function(request, error) {
                alert(request.responseText);
                dump(request.responseText);
            }
        });
    };
 

// Traditional event listeners for the extension
window.addEventListener("load", function () { firedrop.startup(); }, false);
window.addEventListener("unload", function() { firedrop.shutdown(); }, false);